﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace Tron
{
    public partial class GameUserControl : UserControl
    {
        private Graphics paper;
        private int gameCounter;
        private Boolean moved1;
        private Boolean moved2;
        private Player player1;
        private Player player2;
        private Board board;
        private MenuUserControl menu;
        private Label timeLabel;

        public GameUserControl()
        {
            InitializeComponent();

            // INITIALIZE COMPONENTS
            this.components = new System.ComponentModel.Container();
            this.gameTimer = new System.Windows.Forms.Timer(this.components);
            this.boardPanel = new System.Windows.Forms.Panel();
            this.labelTimerCounter = new System.Windows.Forms.Label();
            this.startCountdownTimer = new System.Windows.Forms.Timer(this.components);
            this.labelScore2 = new System.Windows.Forms.Label();
            this.labelScore1 = new System.Windows.Forms.Label();
            this.labelVictory = new System.Windows.Forms.Label();
            this.gamePanel = new System.Windows.Forms.Panel();
            this.gamePanel.SuspendLayout();
            this.SuspendLayout();
            // 
            // gameTimer
            // 
            this.gameTimer.Interval = 50;
            this.gameTimer.Tick += new System.EventHandler(this.timer1_Tick);
            // 
            // boardPanel
            // 
            this.boardPanel.BackColor = System.Drawing.Color.Black;
            this.boardPanel.Location = new System.Drawing.Point(3, 38);
            this.boardPanel.Name = "boardPanel";
            this.boardPanel.Size = new System.Drawing.Size(203, 180);
            this.boardPanel.TabIndex = 0;
            this.boardPanel.Paint += new System.Windows.Forms.PaintEventHandler(this.boardPanel_Paint);
            // 
            // labelTimerCounter
            // 
            this.labelTimerCounter.AutoSize = true;
            this.labelTimerCounter.BackColor = System.Drawing.Color.Black;
            this.labelTimerCounter.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.labelTimerCounter.ForeColor = System.Drawing.Color.White;
            this.labelTimerCounter.Location = new Point((boardPanel.Width - labelTimerCounter.Width) / 2, (boardPanel.Height - labelTimerCounter.Height) / 2);
            this.labelTimerCounter.Name = "labelTimerCounter";
            this.labelTimerCounter.Size = new System.Drawing.Size(0, 31);
            this.labelTimerCounter.TabIndex = 1;
            this.labelTimerCounter.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            this.labelTimerCounter.Visible = false;
            // 
            // startCountdownTimer
            // 
            this.startCountdownTimer.Interval = 500;
            this.startCountdownTimer.Tick += new System.EventHandler(this.countDownTimer_Tick);
            // 
            // labelScore2
            // 
            this.labelScore2.AutoSize = true;
            this.labelScore2.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.labelScore2.ForeColor = System.Drawing.Color.Yellow;
            this.labelScore2.Location = new System.Drawing.Point(176, 10);
            this.labelScore2.Name = "labelScore2";
            this.labelScore2.Size = new System.Drawing.Size(30, 31);
            this.labelScore2.TabIndex = 1;
            this.labelScore2.Text = "0";
            // 
            // labelScore1
            // 
            this.labelScore1.AutoSize = true;
            this.labelScore1.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.labelScore1.ForeColor = System.Drawing.Color.Blue;
            this.labelScore1.Location = new System.Drawing.Point(5, 8);
            this.labelScore1.Name = "labelScore1";
            this.labelScore1.Size = new System.Drawing.Size(30, 31);
            this.labelScore1.TabIndex = 2;
            this.labelScore1.Text = "0";
            // 
            // labelVictory
            // 
            this.labelVictory.AutoSize = true;
            this.labelVictory.Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
            this.labelVictory.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(192)))), ((int)(((byte)(192)))));
            this.labelVictory.Location = new System.Drawing.Point(217, 9);
            this.labelVictory.Name = "labelVictory";
            this.labelVictory.Size = new System.Drawing.Size(0, 31);
            this.labelVictory.TabIndex = 3;
            // 
            // gamePanel
            // 
            this.gamePanel.Controls.Add(this.boardPanel);
            this.gamePanel.Controls.Add(this.labelScore1);
            this.gamePanel.Controls.Add(this.labelScore2);
            this.gamePanel.Controls.Add(this.labelVictory);
            this.gamePanel.Controls.Add(this.menuStrip1);
            this.gamePanel.Controls.Add(this.timeLabel);
            this.gamePanel.Location = new System.Drawing.Point(0, 0);
            this.gamePanel.Name = "gamePanel";
            this.gamePanel.Size = new System.Drawing.Size(223, 221);
            this.gamePanel.TabIndex = 4;

            this.Controls.Add(this.gamePanel);

            this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TronForm_KeyDown);
            this.gamePanel.ResumeLayout(false);
            this.gamePanel.PerformLayout();
            this.ResumeLayout(false);
            this.PerformLayout();

            // Ajout des éléments au panel de jeu
            this.boardPanel.Controls.Add(this.labelTimerCounter);

            // Ajustement des tailles et des positions
            this.boardPanel.Size = new Size(Constantes.Xmatrice * Constantes.tall, Constantes.Ymatrice * Constantes.tall);
            this.boardPanel.Location = new Point(0, 50);
            this.gamePanel.Size = new Size(Constantes.Xmatrice * Constantes.tall, Constantes.Xmatrice * Constantes.tall + 50);
            this.labelScore2.Location = new System.Drawing.Point(boardPanel.Width - 80 - (labelScore2.Width + 5), 8);
            this.labelScore1.Location = new System.Drawing.Point(5 + 80, 8);
            this.labelVictory.Location = new Point((boardPanel.Width - labelTimerCounter.Width) / 2, 10);
            this.labelTimerCounter.Location = new Point((boardPanel.Width - labelTimerCounter.Width) / 2, (boardPanel.Height - labelTimerCounter.Height) / 2);

            gameCounter = 3;
            moved1 = true;
            moved2 = true;
        }

        // Méthode chargé de lancer le jeu sans toucher aux scores
        public void launchGame()
        {
            // Arreter le timer s'il est en marche
            if (gameTimer.Enabled)
                gameTimer.Stop();

            // On nettoie le plateau de jeu
            player1.Moto.MotoRec.Clear();
            player2.Moto.MotoRec.Clear();
            player1.Moto.PictureMoto.Dispose();
            player2.Moto.PictureMoto.Dispose();
            boardPanel.Refresh();

            // Recréation du MODEL
            board = new Board(Constantes.Xmatrice, Constantes.Ymatrice);
            player1.Moto = new Moto(board.Matrix[(int)((Constantes.Xmatrice + 10) / 10),
                                  (int)(Constantes.Ymatrice / 2)].Picture.Location,
                                  (int)Constantes.directions.right,
                                  Color.Blue,
                                  "moto1\\",
                                  board);
            player2.Moto = new Moto(board.Matrix[Constantes.Xmatrice - (int)(Constantes.Xmatrice / 10),
                                  (int)(Constantes.Ymatrice / 2)].Picture.Location,
                                  (int)Constantes.directions.left,
                                  Color.Yellow,
                                  "moto2\\",
                                  board);

            // On ajoute les motos au plateau
            this.boardPanel.Controls.Add(player1.Moto.PictureMoto);
            this.boardPanel.Controls.Add(player2.Moto.PictureMoto);

            this.labelVictory.Text = "";
            labelTimerCounter.Visible = true;

            // Lancement du timer de jeu
            startCountdownTimer.Start();
        }

        public void launchNewGame(Player player1, Player player2)
        {
            this.player1 = player1;
            this.player2 = player2;

            player1.Score = 0;
            player2.Score = 0;
            setScoreLabel(player1, labelScore1);
            setScoreLabel(player2, labelScore2);

            launchGame();
        }



        // Méthode privée gérant les entrées clavier
        private void TronForm_KeyDown(object sender, KeyEventArgs e)
        {
            /*En fonction de la touche utilisée et de la direction de la moto, on donne la nouvelle direction de la moto1*/
            if (e.KeyCode == Keys.Z && player1.Moto.CurrentDirection != (int)Constantes.directions.down && moved1 == true)
            {
                // Changement de la direction
                player1.Moto.CurrentDirection = (int)Constantes.directions.up;
                // Chargement de l'image adaptée à la direction
                player1.Moto.loadImage();
                // Variable temporaire précisant que la nouvelle direction a été donnée
                moved1 = false;
            }
            else if (e.KeyCode == Keys.S && player1.Moto.CurrentDirection != (int)Constantes.directions.up && moved1 == true)
            {
                player1.Moto.CurrentDirection = (int)Constantes.directions.down;
                player1.Moto.loadImage();
                moved1 = false;
            }
            else if (e.KeyCode == Keys.D && player1.Moto.CurrentDirection != (int)Constantes.directions.left && moved1 == true)
            {
                player1.Moto.CurrentDirection = (int)Constantes.directions.right;
                player1.Moto.loadImage();
                moved1 = false;
            }
            else if (e.KeyCode == Keys.Q && player1.Moto.CurrentDirection != (int)Constantes.directions.right && moved1 == true)
            {
                player1.Moto.CurrentDirection = (int)Constantes.directions.left;
                player1.Moto.loadImage();
                moved1 = false;
            }

            /*  Nouvelles directions moto2 */
            if (e.KeyCode == Keys.O && player2.Moto.CurrentDirection != (int)Constantes.directions.down && moved2 == true)
            {
                player2.Moto.CurrentDirection = (int)Constantes.directions.up;
                player2.Moto.loadImage();
                moved2 = false;
            }
            else if (e.KeyCode == Keys.L && player2.Moto.CurrentDirection != (int)Constantes.directions.up && moved2 == true)
            {
                player2.Moto.CurrentDirection = (int)Constantes.directions.down;
                player2.Moto.loadImage();
                moved2 = false;
            }
            else if (e.KeyCode == Keys.M && player2.Moto.CurrentDirection != (int)Constantes.directions.left && moved2 == true)
            {
                player2.Moto.CurrentDirection = (int)Constantes.directions.right;
                player2.Moto.loadImage();
                moved2 = false;
            }
            else if (e.KeyCode == Keys.K && player2.Moto.CurrentDirection != (int)Constantes.directions.right && moved2 == true)
            {
                player2.Moto.CurrentDirection = (int)Constantes.directions.left;
                player2.Moto.loadImage();
                moved2 = false;
            }

            /* Nouvelle partie */
            if (e.KeyCode == Keys.Enter)
            {
                if (player1.Score == 3 || player2.Score == 3)
                    launchNewGame(player1, player2);
                else
                    launchGame();
            }

            //Pause
            if (e.KeyCode == Keys.P && player1.Score < 3 && player2.Score < 3)
            {
                //faire test si il est arrete
                if (gameTimer.Enabled)
                {
                    gameTimer.Stop();
                    labelVictory.Text = "Break";
                    labelVictory.Location = new Point((boardPanel.Width - labelVictory.Width) / 2, 10);
                    labelVictory.Visible = true;
                }
                else
                {
                    //mettre une pause
                    labelVictory.Visible = false;
                    gameCounter = 3;
                    labelTimerCounter.Visible = true;
                    startCountdownTimer.Start();
                }
            }
        }

        /**
         * Lié au timer du plateau de jeu, est appelé à chaque tick du timer.
         * Ici sont faits les tests de collisions des motos.
         */
        private void timer1_Tick(object sender, EventArgs e)
        {
            Boolean moto1Collision = player1.Moto.collide(board);
            Boolean moto2Collision = player2.Moto.collide(board);

            // S'il n'y a pas de collisions alors les motos avancent
            if (!moto1Collision && !moto2Collision)
            {
                player1.Moto.moveOn(board);
                player2.Moto.moveOn(board);
                moved1 = true;
                moved2 = true;
            }
            else
            {
                gameTimer.Stop();
                // Egalité, deux collisions simulanées
                if (moto1Collision && moto2Collision)
                {
                    player1.Score++;
                    player2.Score++;
                    setScoreLabel(this.player1, labelScore1);
                    setScoreLabel(this.player2, labelScore2);
                    if (player1.victoryTest() && player2.victoryTest())
                        labelVictory.Text = "Perfect Equality";
                    else if (player1.victoryTest())
                        labelVictory.Text = player1.Name + " is the winner";
                    else if (player2.victoryTest())
                        labelVictory.Text = player2.Name + " is the winner";
                    else
                        labelVictory.Text = "Equality";
                }
                else if (moto2Collision)
                {
                    player1.Score++;
                    setScoreLabel(this.player1, labelScore1);
                    if (player1.victoryTest())
                        labelVictory.Text = player1.Name + " is the winner";
                    else
                        labelVictory.Text = player1.Name + " wins";
                }
                else if (moto1Collision)
                {
                    player2.Score++;
                    setScoreLabel(this.player2, labelScore2);
                    if (player2.victoryTest())
                        labelVictory.Text = player2.Name + " is the winner";
                    else
                        labelVictory.Text = player2.Name + " wins";
                }

                labelVictory.Location = new Point((boardPanel.Width - labelVictory.Width) / 2, 10);
                labelVictory.Visible = true;
            }
        }

        /**
         * Met à jour le label de score d'un joueur donné
         * 
         * Player player: joueur
         * Label label: label lié au joueur
         * return void
         */ 
        private void setScoreLabel(Player player, Label label)
        {
            label.Text = player.Score.ToString() + "/" + Constantes.scoreToWin;
        }

        /**
         * Méthode liée au timer de départ du jeu. 
         * Egalement utilisé à la reprise d'une partie en pause.
         */
        private void countDownTimer_Tick(object sender, EventArgs e)
        {
            if (gameCounter == 0)
            {
                labelTimerCounter.Visible = false;
                gameCounter = 3;
                startCountdownTimer.Stop();
                gameTimer.Start();
            }

            labelTimerCounter.Text = gameCounter.ToString();
            gameCounter--;
        }

        private void boardPanel_Paint(object sender, PaintEventArgs e)
        {
            // On créé un graphic basé sur le PaintEventArgs
            paper = e.Graphics;
            // On dessine la trainée des deux motos
            player1.Moto.drawLine(paper);
            player2.Moto.drawLine(paper);

            this.Invalidate();
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void helpToolStripMenuItem_Click(object sender, EventArgs e)
        {
            launchNewGame(player1, player2);
        }

        private void menuToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Visible = !this.Visible;
            menu.Visible = !menu.Visible;
        }

        public MenuUserControl Menu
        {
            get
            {
                return menu;
            }
            set
            {
                menu = value;
            }
        }

        public Label TimeLabel
        {
            get
            {
                return timeLabel;
            }
            set
            {
                timeLabel = value;
            }
        }
    }
}
